#include "TerrainEffects.h"

Effect::TerrainEffects::TerrainEffects()
	:m_pDevice(NULL)
	,m_pFx(NULL)
	,m_pInputLayout(NULL)
	,m_pFxTech(NULL)
	,m_pFxWVPVar(NULL)
	,m_pFxWorldVar(NULL)
	,m_pFxDirToSunVar(NULL)
	,m_pFxLayer0Var(NULL)
	,m_pFxLayer1Var(NULL)
	,m_pFxLayer2Var(NULL)
	,m_pFxLayer3Var(NULL)
	,m_pFxLayer4Var(NULL)
	,m_pFxBlendMapVar(NULL)
{

}

Effect::TerrainEffects::~TerrainEffects()
{
	ReleaseCOM(m_pInputLayout);
	ReleaseCOM(m_pFx);
}

void Effect::TerrainEffects::SetDirectionToSun( const D3DXVECTOR4& dir )
{
	D3DXVECTOR4 temp(dir.x, dir.y, dir.z, 0.0f);
	m_pFxDirToSunVar->SetFloatVector((float*)temp);
}

void Effect::TerrainEffects::SetWVPMatrix( const D3DXMATRIX& mat )
{
	m_pFxWVPVar->SetMatrix((float*)&mat);
}

void Effect::TerrainEffects::SetWorldMatrix( const D3DXMATRIX& mat )
{
	m_pFxWorldVar->SetMatrix((float*)&mat);
}

void Effect::TerrainEffects::SetLayer0( ID3D10ShaderResourceView* resView )
{
	m_pFxLayer0Var->SetResource(resView);
}

void Effect::TerrainEffects::SetLayer1( ID3D10ShaderResourceView* resView )
{
	m_pFxLayer1Var->SetResource(resView);
}

void Effect::TerrainEffects::SetLayer2( ID3D10ShaderResourceView* resView )
{
	m_pFxLayer2Var->SetResource(resView);
}

void Effect::TerrainEffects::SetLayer3( ID3D10ShaderResourceView* resView )
{
	m_pFxLayer3Var->SetResource(resView);
}

void Effect::TerrainEffects::SetLayer4( ID3D10ShaderResourceView* resView )
{
	m_pFxLayer4Var->SetResource(resView);
}

void Effect::TerrainEffects::SetBlendMap( ID3D10ShaderResourceView* resView )
{
	m_pFxBlendMapVar->SetResource(resView);
}

void Effect::TerrainEffects::SetVertexBuffer( ID3D10Buffer* buffer )
{
	UINT stride = sizeof(Vertex);
	UINT offset = 0;
	m_pDevice->IASetVertexBuffers(0, 1, &buffer, &stride, &offset);
}

void Effect::TerrainEffects::SetIndexBuffer( ID3D10Buffer* buffer )
{
	m_pDevice->IASetIndexBuffer(buffer, DXGI_FORMAT_R32_UINT, 0);
}

void Effect::TerrainEffects::Draw( UINT numFaces )
{
	D3D10_TECHNIQUE_DESC techDesc;
	m_pFxTech->GetDesc( &techDesc );

	for(UINT i = 0; i < techDesc.Passes; ++i)
	{
		ID3D10EffectPass* pass = m_pFxTech->GetPassByIndex(i);
		pass->Apply(0);

		m_pDevice->DrawIndexed(numFaces*3, 0, 0);
	}	
}

void Effect::TerrainEffects::Init( ID3D10Device* device )
{

	m_pDevice = device;

	BuildFX();
	BuildVertexLayouts();
}

void Effect::TerrainEffects::BuildFX()
{
	DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
	shaderFlags |= D3D10_SHADER_DEBUG;
	shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;
#endif

	ID3D10Blob* compilationErrors = 0;
	HRESULT hr = 0;
	hr = D3DX10CreateEffectFromFile(L"Terrain.fx", 0, 0, 
		"fx_4_0", shaderFlags, 0, m_pDevice, 0, 0, &m_pFx, &compilationErrors, 0);
	if(FAILED(hr))
	{
		if( compilationErrors )
		{
			MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0);
			ReleaseCOM(compilationErrors);
		}
		DXTrace(__FILE__, (DWORD)__LINE__, hr, L"D3DX10CreateEffectFromFile", true);
	} 

	m_pFxTech = m_pFx->GetTechniqueByName("TerrainTech");

	m_pFxWVPVar        = m_pFx->GetVariableByName("gWVP")->AsMatrix();
	m_pFxWorldVar      = m_pFx->GetVariableByName("gWorld")->AsMatrix();

	m_pFxDirToSunVar = m_pFx->GetVariableByName("gDirToSun")->AsVector();
	m_pFxLayer0Var   = m_pFx->GetVariableByName("gLayer0")->AsShaderResource();
	m_pFxLayer1Var   = m_pFx->GetVariableByName("gLayer1")->AsShaderResource();
	m_pFxLayer2Var   = m_pFx->GetVariableByName("gLayer2")->AsShaderResource();
	m_pFxLayer3Var   = m_pFx->GetVariableByName("gLayer3")->AsShaderResource();
	m_pFxLayer4Var   = m_pFx->GetVariableByName("gLayer4")->AsShaderResource();
	m_pFxBlendMapVar = m_pFx->GetVariableByName("gBlendMap")->AsShaderResource();
}

void Effect::TerrainEffects::BuildVertexLayouts()
{
	// Create the vertex input layout.
	D3D10_INPUT_ELEMENT_DESC vertexDesc[] =
	{
		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0},
	};

	// Create the input layout
	D3D10_PASS_DESC PassDesc;
	m_pFxTech->GetPassByIndex(0)->GetDesc(&PassDesc);
	HR(m_pDevice->CreateInputLayout(vertexDesc, 3, PassDesc.pIAInputSignature,
		PassDesc.IAInputSignatureSize, &m_pInputLayout));
}

void Effect::TerrainEffects::BeginDraw()
{
	m_pDevice->IASetInputLayout(m_pInputLayout);
	m_pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
